package test.y2021;

import cn.hutool.core.lang.Console;

import java.util.concurrent.atomic.AtomicLong;

/**
 * Created By  醉美柳舞之众星捧月
 *
 * @author song
 * @date 2021/1/28 16:08
 */
public class January1 {
    public static void main(String[] args) {

        IdGenerator2 instance1 = IdGenerator2.getInstance();
        Console.error(instance1);

        IdGenerator2 instance2 = IdGenerator2.getInstance();
        Console.error(instance2);

        IdGenerator3 instance3 = IdGenerator3.getInstance();
        Console.error(instance3.getId());

    }
}

class IdGenerator1 {
    /* 懒汉式相对于饿汉式的优势是支持延迟加载。这种实现方式会导致频繁加锁、释放锁，以及并发度低等问题，频繁的调用会产生性能瓶颈。 */
    private AtomicLong id = new AtomicLong(0);
    private static IdGenerator1 instance;

    private IdGenerator1() {
    }

    public static synchronized IdGenerator1 getInstance() {
        if (instance == null) {
            instance = new IdGenerator1();
        }
        return instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}

class IdGenerator2 {
    /* 双重检测实现方式既支持延迟加载、又支持高并发的单例实现方式。只要 instance 被创建之后，再调用 getInstance() 函数都不会进入到加锁逻辑中。所以，这种实现方式解决了懒汉式并发度低的问题。 */
    private AtomicLong id = new AtomicLong(0);
    private static IdGenerator2 instance;

    private IdGenerator2() {
    }

    public static IdGenerator2 getInstance() {
        if (instance == null) {
            synchronized (IdGenerator2.class) {
                // 此处为类级别的锁
                if (instance == null) {
                    instance = new IdGenerator2();
                }
            }
        }
        return instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}

class IdGenerator3 {
    /* 利用 Java 的静态内部类来实现单例。这种实现方式，既支持延迟加载，也支持高并发，实现起来也比双重检测简单 */
    private AtomicLong id = new AtomicLong(0);

    private IdGenerator3() {
    }

    private static class SingletonHolder {
        private static final IdGenerator3 instance = new IdGenerator3();
    }

    public static IdGenerator3 getInstance() {
        return SingletonHolder.instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}